package com.zzh.lib.htts;

import android.app.Application;
import android.content.Context;
import android.os.Bundle;
import android.speech.tts.TextToSpeech;
import android.text.TextUtils;
import android.util.DisplayMetrics;

import com.zzh.lib.htts.callback.OnSetParamsCallback;
import com.zzh.lib.htts.callback.OnUtteranceProgressListener;
import com.zzh.lib.htts.params.HTTSParams;
import com.zzh.lib.recorder.HMediaRecorder;
import com.zzh.lib.recorder.HMediaRecorderParams;
import com.zzh.lib.recorder.def.IRecorder;
import com.zzh.lib.recorder.mp3.Mp3Recorder;
import com.zzh.lib.recorder.pcm.PCMRecorder;

import java.util.LinkedList;
import java.util.Locale;

/**
 * Created by ZZH on 5/10/21.
 *
 * @Date: 5/10/21
 * @Email: zzh_hz@126.com
 * @QQ: 1299234582
 * @Author: zzh
 * @Description: 语音播报
 */
public class HTTSLib {

    static final public String KEY_UNIQUE_ID = "hUniqueID";
    private Context ctx;
    private static final LinkedList<TextToSpeech> cacheTts = new LinkedList<>();
    private HTTSParams ttsParams;

    private HTTSLib() {
    }

    private boolean isSupportTTS = false;
    private boolean isSetVaeVoice = false;

    private static volatile HTTSLib mInstance;

    private TextToSpeech mTextToSpeech;

    private OnSetParamsCallback mCallback;

    public TextToSpeech getTextToSpeech() {
        return mTextToSpeech;
    }

    public static HTTSLib getInstance() {
        if (mInstance == null) {
            synchronized (HTTSLib.class) {
                if (mInstance == null) {
                    return mInstance = new HTTSLib();
                }
            }
        }
        return mInstance;
    }

    public HTTSLib setCallback(OnSetParamsCallback callback) {
        mCallback = callback;
        return this;
    }

    public boolean isSupportTTS() {
        return isSupportTTS;
    }

    /**
     * 初始化语音播放
     *
     * @param atx      当前上下文
     * @param listener 初始化结果监听 {@link TextToSpeech#SUCCESS} or {@link TextToSpeech#ERROR}.
     */
    public HTTSLib init(Context atx, TextToSpeech.OnInitListener listener) {
        initText2Speech(atx, listener);
        return mInstance;
    }

    /**
     * @param atx 上下文
     * @return HTTSLib实例
     * @see HTTSLib#init(Context, TextToSpeech.OnInitListener)
     */
    public HTTSLib init(Context atx) {
        initText2Speech(atx, null);
        return mInstance;
    }

    /**
     * @see HTTSLib#init(Context, TextToSpeech.OnInitListener)
     */
    public HTTSLib newInitSpeech(Context ctx, TextToSpeech.OnInitListener listener) {
        init(ctx, listener);
        return mInstance;
    }

    /**
     * @see HTTSLib#init(Context)
     */
    public HTTSLib newInitSpeech(Context ctx) {
        init(ctx);
        return mInstance;
    }

    private void initText2Speech(Context atx, TextToSpeech.OnInitListener listener) {
        this.ctx = atx;
        mTextToSpeech = new TextToSpeech(atx, status -> {
            isSupportTTS = status == TextToSpeech.SUCCESS;
            if (isSupportTTS) {
                cacheTts.add(mTextToSpeech);
            }
            if (listener != null) {
                listener.onInit(status);
            }
        });
        setVaeVoiceParams();
    }

    /**
     * 播放语音，默认播放中文
     *
     * @param cs         需要播放的文字
     * @param queueModel 播放模式
     * @param params     播放参数
     * @param uniqueId   本次语音播放的唯一ID
     * @return 成功返回 0
     */
    public int speak(CharSequence cs, int queueModel, Bundle params, String uniqueId, OnUtteranceProgressListener listener) {
        if (TextUtils.isEmpty(cs)) {
            return 99;
        }
        if (mTextToSpeech == null) {
            if (!cacheTts.isEmpty()) {
                mTextToSpeech = cacheTts.get(cacheTts.size() - 1);
            } else {
                init(ctx);
            }
        }

        if (mTextToSpeech == null) {
            return 10;
        }

        mTextToSpeech.setOnUtteranceProgressListener(listener);
        if (isSetVaeVoice && ttsParams != null) {
            setVaeVoiceParams();
        }
        int speak = mTextToSpeech.speak(cs, queueModel, params, uniqueId);
        if (speak == TextToSpeech.ERROR) {
            newInitSpeech(ctx, status -> mTextToSpeech.speak(cs, queueModel, params, uniqueId));
        }
        return speak;

    }

    private void setVaeVoiceParams() {
        isSetVaeVoice = false;
        if (ttsParams == null) {
            return;
        }
        mTextToSpeech.setPitch(ttsParams.pitch);
        if (ttsParams.loc != null) {
            mTextToSpeech.setLanguage(ttsParams.loc);
        }
        mTextToSpeech.setSpeechRate(ttsParams.speechRate);

        if (ttsParams.audioAttributes != null) {
            mTextToSpeech.setAudioAttributes(ttsParams.audioAttributes);
        }
        if (ttsParams.defaultVoice != null) {
            mTextToSpeech.setVoice(ttsParams.defaultVoice);
        }
    }

    /**
     * 播放语音，默认播放中文
     * {@link HTTSLib#speak(CharSequence, int, Bundle, String, OnUtteranceProgressListener)} }
     */
    public int speak(CharSequence cs) {
        return speak(cs, TextToSpeech.QUEUE_FLUSH, null, KEY_UNIQUE_ID, null);
    }

    public int speak(CharSequence cs, OnUtteranceProgressListener listener) {
        return speak(cs, TextToSpeech.QUEUE_FLUSH, null, KEY_UNIQUE_ID, listener);
    }

    public int speak(CharSequence cs, int queueModel) {
        return speak(cs, queueModel, null, KEY_UNIQUE_ID, null);
    }

    public int speak(CharSequence cs, int queueModel, OnUtteranceProgressListener listener) {
        return speak(cs, queueModel, null, KEY_UNIQUE_ID, listener);
    }

    /**
     * {@link HTTSLib#speak(CharSequence, int, Bundle, String, OnUtteranceProgressListener)} }
     */
    public int speak(CharSequence cs, int queueModel, Bundle params) {
        return speak(cs, queueModel, params, KEY_UNIQUE_ID, null);
    }


    /**
     * 释放当前资源。mTextToSpeech 指向队列中最后一个变量
     */
    public void releaseCurrentTTS() {
        try {
            if (mTextToSpeech != null) {
                mTextToSpeech.stop();
                mTextToSpeech.shutdown();
                mTextToSpeech = null;
                cacheTts.removeLast();
            }
        } catch (Exception ignored) {

        }

        if (cacheTts.size() > 0) {
            mTextToSpeech = cacheTts.getLast();
        }
    }

    /**
     * 释放资源
     */
    public void release() {

        try {
            if (mTextToSpeech != null) {
                mTextToSpeech.stop();
                mTextToSpeech.shutdown();
                mTextToSpeech = null;
            }

            if (!cacheTts.isEmpty()) {
                for (TextToSpeech tts : cacheTts) {
                    if (tts != null) {
                        tts.stop();
                        tts.shutdown();
                        tts = null;
                    }
                }
                cacheTts.clear();
            }
        } catch (Exception ex) {
            ex.printStackTrace();
        }

    }

    /**
     * 设置TTS参数
     *
     * @param params TTS参数
     * @return this
     */
    public HTTSLib setParams(HTTSParams params) {
        ttsParams = params;
        isSetVaeVoice = true;
        return mInstance;
    }

    /**
     * 是否正在播报
     *
     * @return true 是
     */
    public boolean isSpeak() {
        return mTextToSpeech != null && mTextToSpeech.isSpeaking();
    }

    /**
     * 判断是否支持某种语言
     *
     * @param loc 语言
     * @return Code indicating the support status for the locale. See {@link TextToSpeech#LANG_AVAILABLE},
     * {@link TextToSpeech#LANG_COUNTRY_AVAILABLE}, {@link TextToSpeech#LANG_COUNTRY_VAR_AVAILABLE},
     * {@link TextToSpeech#LANG_MISSING_DATA} and {@link TextToSpeech#LANG_NOT_SUPPORTED}.
     */
    public int isLangAvailable(Locale loc) {
        return mTextToSpeech == null ? TextToSpeech.ERROR : mTextToSpeech.isLanguageAvailable(loc);
    }

    /**
     * 停止
     *
     * @return {@link TextToSpeech#stop()}
     */
    public int stop() {
        if (mTextToSpeech != null) {
            return mTextToSpeech.stop();
        }
        return TextToSpeech.ERROR;
    }

    /**
     * {@link TextToSpeech#shutdown()}
     */
    public void shutdown() {
        if (mTextToSpeech != null) {
            mTextToSpeech.shutdown();
        }
    }


    private HMediaRecorderParams mRecorderParams;


    public HMediaRecorderParams getRecorderParams() {
        return mRecorderParams;
    }

    public HTTSLib setRecorderParams(HMediaRecorderParams recorderParams) {
        mRecorderParams = recorderParams;
        return this;
    }

    public IRecorder create() {
        if (mRecorderParams != null && mRecorderParams.getAudioEncoder() == 4000) {
            return initPcmRecorder();
        } else if (mRecorderParams != null && mRecorderParams.getAudioEncoder() == 3000) {
            return initMp3Recorder();
        } else {
            return initMRecorder();
        }
    }

    private IRecorder initPcmRecorder() {
        return new PCMRecorder(mRecorderParams);
    }

    private IRecorder initMRecorder() {
        HMediaRecorder hMediaRecorder = new HMediaRecorder();
        hMediaRecorder.setRecorderParams(mRecorderParams);
        hMediaRecorder.init();
        return hMediaRecorder;
    }

    private IRecorder initMp3Recorder() {
        Mp3Recorder mp3Recorder = new Mp3Recorder();
        if (mRecorderParams == null) {
            mRecorderParams = HMediaRecorderParams.buildDefaultPCM();
        }
        mp3Recorder.setRecorderParams(mRecorderParams);
        return mp3Recorder;
    }

    Application mApplication;

    public static int screenWidth;
    public static int screenHeight;

    public static Application getContext() {
        if (getInstance().mApplication == null) {
            throw new NullPointerException("mApplication == null");
        }
        return getInstance().mApplication;
    }

    public void registerApplication(Application application) {
        mApplication = application;
        DisplayMetrics mDisplayMetrics = mApplication.getResources().getDisplayMetrics();
        screenWidth = mDisplayMetrics.widthPixels;
        screenHeight = mDisplayMetrics.heightPixels;
    }


}
